/* 
 * ChamadoDAO.java
 * Copyright (c) Faculdade Anhanguera de Anápolis.
 * Tecnologia em Análise e Desenvolvimento de Sistemas.
 * Projeto Multidisciplinar de Autoaprendizagem.
 *
 * Este software é confidencial e propriedade da Faculdade Anhanguera de Anápolis.
 * Não é permitida sua distribuição ou divulgação do seu conteúdo sem expressa autorização da Faculdade Anhanguera de Anápolis.
 * Este arquivo contém informações proprietárias.
 */
package br.com.pma.chamatec.dao;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import br.com.pma.chamatec.dominio.PerfilUsuario;
import br.com.pma.chamatec.exception.ChamatecNegocioException;
import br.com.pma.entity.Chamado;
import br.com.pma.entity.Departamento;
import br.com.pma.entity.Unidade;
import br.com.pma.entity.Usuario;

/**
 * DAO de acesso a dados da tabela Chamado.
 *
 * @author Ludemeula Fernandes de Sá
 */
public class ChamadoDAO extends GenericChamatecDAO<Chamado> {
	private static final long serialVersionUID = 6155513372253235558L;

	/**
	 * Lista os dados da tabela Chamado pela descrição.
	 * 
	 * @return
	 * @throws ChamatecNegocioException
	 */
	public List<Chamado> getListDescricao() throws ChamatecNegocioException {
		List<Chamado> retorno = null;

		try { 
			CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
			CriteriaQuery<Chamado> criteriaQuery = criteriaBuilder.createQuery(Chamado.class);
			Root<Chamado> root = criteriaQuery.from(Chamado.class);
			List<Predicate> condicoes = new ArrayList<Predicate>();

			Predicate whereAutorizado = criteriaBuilder.equal(root.get("situacao"), 1L);
			condicoes.add(whereAutorizado);

			Predicate whereExecutado = criteriaBuilder.equal(root.get("isExecutado"), 0L);
			condicoes.add(whereExecutado);

			root.fetch("unidade");
			root.fetch("departamento");
			root.fetch("usuarioSolicitacao");
			root.fetch("usuarioAutorizacao", JoinType.LEFT);
			criteriaQuery.where(condicoes.toArray(new Predicate[] {}));
			criteriaQuery.select(root).orderBy(criteriaBuilder.asc(root.get("resumo")));
			retorno = getEntityManager().createQuery(criteriaQuery).getResultList();
		} catch (Exception e) {
			throw new ChamatecNegocioException(e);
		}

		return retorno;
	}

	/**
	 * Pesquisa todas as ordens de serviço em aberto.
	 * 
	 * @param chamado
	 * @param usuario
	 * @return
	 * @throws ChamatecNegocioException
	 */
	public List<Chamado> pesquisar(Chamado chamado, Usuario solicitante, Usuario usuario) throws ChamatecNegocioException {
		List<Chamado> retorno = null;
		try {
			CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
			CriteriaQuery<Chamado> criteriaQuery = criteriaBuilder.createQuery(Chamado.class);
			Root<Chamado> root = criteriaQuery.from(Chamado.class);
			List<Predicate> condicoes = new ArrayList<Predicate>();
			
			if (chamado != null || solicitante != null) {
			
				if (chamado.getResumo() != null && !chamado.getResumo().equals("")) {
					Predicate whereResumo = criteriaBuilder.like(root.<String>get("resumo"), "%" + chamado.getResumo() + "%");
					condicoes.add(whereResumo);
				}
	
				if (solicitante != null && solicitante.getNome() != null && !solicitante.getNome().equals("")) {
					Join<Chamado, Usuario> chamadoUsuario = root.join("usuarioSolicitacao", JoinType.INNER);
					Predicate whereUsuarioSolicitacao = criteriaBuilder.like(chamadoUsuario.<String>get("nome"), "%" + solicitante.getNome() + "%");
					condicoes.add(whereUsuarioSolicitacao);
				}
	
				if (chamado.getUnidade() != null && chamado.getUnidade().getId() != null && chamado.getUnidade().getId() != 0) {
					Predicate whereUnidade = criteriaBuilder.equal(root.get("unidade"), chamado.getUnidade());
					condicoes.add(whereUnidade);
				}
	
				if (chamado.getDepartamento() != null && chamado.getDepartamento().getId() != null && chamado.getDepartamento().getId() != 0) {
					Predicate whereResumo = criteriaBuilder.equal(root.get("departamento"), chamado.getDepartamento());
					condicoes.add(whereResumo);
				}
			}

			if (usuario.getPerfil().getNome().equals(PerfilUsuario.SERVIDOR.getDescricao())) {
				Predicate whereServidor = criteriaBuilder.equal(root.get("usuarioSolicitacao"), usuario);
				condicoes.add(whereServidor);
			}

			Predicate whereAutorizado = criteriaBuilder.equal(root.get("isAutorizado"), 0L);
			condicoes.add(whereAutorizado);
			
			root.fetch("unidade");
			root.fetch("departamento");
			root.fetch("usuarioSolicitacao");
			root.fetch("usuarioAutorizacao", JoinType.LEFT);
			criteriaQuery.where(condicoes.toArray(new Predicate[] {}));
			criteriaQuery.select(root).orderBy(criteriaBuilder.asc(root.get("resumo")));
			retorno = getEntityManager().createQuery(criteriaQuery).getResultList();
		} catch (Exception e) {
			throw new ChamatecNegocioException(e);
		}
		return retorno;
	}

	/**
	 * Pesquisa todas as ordens de serviço autorizadas.
	 * 
	 * @param chamado
	 * @param usuario
	 * @return
	 * @throws ChamatecNegocioException
	 */
	public List<Chamado> acompanhar(Chamado chamado, Usuario solicitante, Usuario usuario) throws ChamatecNegocioException {
		List<Chamado> retorno = null;
		try {
			CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
			CriteriaQuery<Chamado> criteriaQuery = criteriaBuilder.createQuery(Chamado.class);
			Root<Chamado> root = criteriaQuery.from(Chamado.class);
			List<Predicate> condicoes = new ArrayList<Predicate>();

			if (chamado != null) {
				if (chamado.getResumo() != null && !chamado.getResumo().equals("")) {
					Predicate whereResumo = criteriaBuilder.like(root.<String>get("resumo"), "%" + chamado.getResumo() + "%");
					condicoes.add(whereResumo);
				}

				if (solicitante != null && solicitante.getNome() != null && !solicitante.getNome().equals("")) {
					Join<Chamado, Usuario> chamadoUsuario = root.join("usuarioSolicitacao", JoinType.INNER);
					Predicate whereUsuarioSolicitacao = criteriaBuilder.like(chamadoUsuario.<String>get("nome"), "%" + solicitante.getNome() + "%");
					condicoes.add(whereUsuarioSolicitacao);
				}

				if (chamado.getUnidade() != null && chamado.getUnidade().getId() != null && chamado.getUnidade().getId() != 0) {
					Predicate whereUnidade = criteriaBuilder.equal(root.get("unidade"), chamado.getUnidade());
					condicoes.add(whereUnidade);
				}

				if (chamado.getDepartamento() != null && chamado.getDepartamento().getId() != null && chamado.getDepartamento().getId() != 0) {
					Predicate whereResumo = criteriaBuilder.equal(root.get("departamento"), chamado.getDepartamento());
					condicoes.add(whereResumo);
				}
			}

			if (usuario.getPerfil().getNome().equals(PerfilUsuario.SERVIDOR.getDescricao())) {
				Predicate whereServidor = criteriaBuilder.equal(root.get("usuarioSolicitacao"), usuario);
				condicoes.add(whereServidor);
			}

			Predicate whereAutorizado = criteriaBuilder.equal(root.get("isAutorizado"), 1L);
			condicoes.add(whereAutorizado);

			Predicate whereExecutado = criteriaBuilder.equal(root.get("isExecutado"), 0L);
			condicoes.add(whereExecutado);
			
			root.fetch("unidade");
			root.fetch("departamento");
			root.fetch("usuarioSolicitacao");
			root.fetch("usuarioAutorizacao", JoinType.LEFT);
			criteriaQuery.where(condicoes.toArray(new Predicate[] {}));
			criteriaQuery.select(root).orderBy(criteriaBuilder.asc(root.get("resumo")));
			retorno = getEntityManager().createQuery(criteriaQuery).getResultList();
		} catch (Exception e) {
			throw new ChamatecNegocioException(e);
		}
		return retorno;
	}

	/**
	 *  Gera o relatório de chamados com base nos filtros informados.
	 * 
	 * @param chamado
	 * @param dataInicial
	 * @param dataFinal
	 * @return
	 * @throws ChamatecNegocioException
	 */
	public List<Chamado> gerar(Chamado chamado, final Date dataInicial, final Date dataFinal) throws ChamatecNegocioException {
		List<Chamado> retorno = null;
		try {
			CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
			CriteriaQuery<Chamado> criteriaQuery = criteriaBuilder.createQuery(Chamado.class);
			Root<Chamado> root = criteriaQuery.from(Chamado.class);
			List<Predicate> condicoes = new ArrayList<Predicate>();

			Predicate whereData = criteriaBuilder.between(root.<Date>get("dataAbertura"), dataInicial, dataFinal);
			condicoes.add(whereData);
			
			root.fetch("unidade");
			root.fetch("departamento");
			root.fetch("usuarioSolicitacao");
			root.fetch("usuarioAutorizacao", JoinType.LEFT);
			criteriaQuery.where(condicoes.toArray(new Predicate[] {}));
			criteriaQuery.select(root).orderBy(criteriaBuilder.asc(root.get("resumo")));
			retorno = getEntityManager().createQuery(criteriaQuery).getResultList();
		} catch (Exception e) {
			throw new ChamatecNegocioException(e);
		}
		return retorno;
	}

	/**
	 * Pesquisa os dados de Chamado vinculados com unidades.
	 * 
	 * @param unidade
	 * @return
	 * @throws ChamatecNegocioException
	 */
	public List<Chamado> pesquisarPorUnidade(Unidade unidade) throws ChamatecNegocioException {
		List<Chamado> retorno = null;
		try {
			CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
			CriteriaQuery<Chamado> criteria = builder.createQuery(Chamado.class);
			Root<Chamado> root = criteria.from(Chamado.class);

			Predicate whereUnidade = builder.equal(root.get("unidade"), unidade);
			criteria.where(whereUnidade);

			criteria.select(root).orderBy(builder.asc(root.get("id")));
			retorno = getEntityManager().createQuery(criteria).getResultList();
		} catch (Exception e) {
			throw new ChamatecNegocioException(e);
		}

		return retorno;
	}

	/**
	 * Pesquisa os dados de Chamado vinculados com departamentos.
	 * 
	 * @param departamento
	 * @return
	 * @throws ChamatecNegocioException
	 */
	public List<Chamado> pesquisarPorDepartamento(Departamento departamento) throws ChamatecNegocioException {
		List<Chamado> retorno = null;
		try {
			CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
			CriteriaQuery<Chamado> criteria = builder.createQuery(Chamado.class);
			Root<Chamado> root = criteria.from(Chamado.class);

			Predicate whereDepartamento = builder.equal(root.get("departamento"), departamento);
			criteria.where(whereDepartamento);

			criteria.select(root).orderBy(builder.asc(root.get("id")));
			retorno = getEntityManager().createQuery(criteria).getResultList();
		} catch (Exception e) {
			throw new ChamatecNegocioException(e);
		}

		return retorno;
	}

	/**
	 * Pesquisa os dados de Chamado vinculados com usuários.
	 * 
	 * @param usuario
	 * @return
	 * @throws ChamatecNegocioException
	 */
	public List<Chamado> pesquisarPorUsuario(Usuario usuario) throws ChamatecNegocioException {
		List<Chamado> retorno = null;
		try {
			CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
			CriteriaQuery<Chamado> criteria = builder.createQuery(Chamado.class);
			Root<Chamado> root = criteria.from(Chamado.class);

			Predicate whereUsuarioSolicitacao = builder.equal(root.get("usuarioSolicitacao"), usuario);
			criteria.where(whereUsuarioSolicitacao);

			Predicate whereUsuarioAutorizacao = builder.equal(root.get("usuarioAutorizacao"), usuario);
			criteria.where(whereUsuarioAutorizacao);

			root.fetch("usuarioSolicitacao");
			root.fetch("usuarioAutorizacao", JoinType.LEFT);
			criteria.select(root).orderBy(builder.asc(root.get("id")));
			retorno = getEntityManager().createQuery(criteria).getResultList();
		} catch (Exception e) {
			throw new ChamatecNegocioException(e);
		}

		return retorno;
	}
}